// use quic_secs_driver::secs2::Message;

// use crate::{AppError, AppResult};

// pub(crate) fn parse_json_to_message(json: serde_json::Value) -> AppResult<Message> {
//     // let s = json.serialize("serializer");
//     if !json.is_object() {
//         return Err(AppError::Message("message is not object".to_string()));
//     }
//     let s: u8 = json
//         .get("s")
//         .ok_or(AppError::Message("couldn't read stream".to_string()))?
//         .as_u64()
//         .ok_or(AppError::Message(
//             "the value of stream is not number".to_string(),
//         ))?
//         .try_into()
//         .or_else(|x| Err(AppError::Message(format!("stream is invalid, {:?}", x))))?;
//     // let f = json
//     //     .get("f")
//     //     .ok_or(AppError::Message("couldn't read function".to_string()))?;
//     let result = Message::new(0, 0, true);
//     Ok(result)
// }

// #[test]
// fn test_serialize() {
//     let json = serde_json::json!({
//         "s": 0,
//         "f": 0,
//         "d": "hello"
//     });
//     let s = json.get("s").unwrap().as_u64().unwrap();
//     println!("{:?}", s);
// }

use std::sync::{atomic::AtomicU64, Arc};

use chrono::Local;
use quic_secs_driver::secs2::{Message, MessageWrapperForReceived, Value};

use crate::models::{MatchPolicy, MessageFlagPattern, Preference, TransactionTemplate};

// macro_rules! fill_ceid_inner {
//     ($value:expr, $name:expr,$desc:expr,$format:expr, $source:expr) => {
//         if let Some(val) = $value.get(0) {
//             if let Some(name) = $name {
//                 if name == STR_CEID {
//                     let val = val.to_string();
//                     for item in $source.iter() {
//                         if item.format == $format && item.id == val {
//                             append_option_str($desc, &item.desc);
//                             break;
//                         }
//                     }
//                 }
//             }
//         }
//     };
// }

const STR_CEID: &'static str = "CEID";
// const STR_VID: &'static str = "VID";

macro_rules! fill_ceid_describe {
    ($value:expr_2021, $name:expr_2021,$desc:expr_2021,$format:expr_2021,$is_match_ceid:expr_2021,$is_match_vid:expr_2021, $preference:expr_2021) => {
        if let Some(pre) = $preference {
            if let Some(val) = $value.get(0) {
                if let Some(name) = $name {
                    let val = val.to_string();
                    if $is_match_ceid && name == STR_CEID {
                        for item in pre.collection_event.items.iter() {
                            if item.format == $format && item.id == val {
                                append_option_str($desc, &item.desc);
                                return;
                            }
                        }
                    }
                    // if is_match_vid && name == STR_VID {
                    //     for item in pre.variable.items.iter() {
                    //         if item.format == $format && item.id == val {
                    //             append_option_str(desc, &item.desc);
                    //             return;
                    //         }
                    //     }
                    // }
                    for item in pre.mappings.iter() {
                        if &item.name == name {
                            for sub_item in item.mappings.iter() {
                                if sub_item.format == $format && sub_item.value == val {
                                    append_option_str($desc, &sub_item.desc);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
    };
    ($value:expr_2021, $name:expr_2021,$desc:expr_2021,$format:expr_2021,$is_match_ceid:expr_2021,$is_match_vid:expr_2021, $preference:expr_2021,$flag:expr_2021) => {
        if let Some(pre) = $preference {
            if let Some(name) = $name {
                if name == STR_CEID {
                    for item in pre.collection_event.items.iter() {
                        if item.format == $format && &item.id == $value {
                            append_option_str($desc, &item.desc);
                            break;
                        }
                    }
                }
                for item in pre.mappings.iter() {
                    if &item.name == name {
                        for sub_item in item.mappings.iter() {
                            if sub_item.format == $format && &sub_item.value == $value {
                                append_option_str($desc, &sub_item.desc);
                                return;
                            }
                        }
                    }
                }
            }
        }
    };
}

#[inline]
pub(crate) fn get_log_time() -> String {
    chrono::Local::now()
        .format("%Y-%m-%d %H:%M:%S.%3f")
        .to_string()
}

pub(crate) fn format_time_h_m_s_3f(time: &chrono::DateTime<Local>) -> String {
    time.format("%H:%M:%S.%3f").to_string()
}

#[inline]
pub(crate) fn format_time_full(time: &chrono::DateTime<Local>) -> String {
    time.format("%Y-%m-%d %H:%M:%S.%3f").to_string()
}

#[allow(dead_code)]
pub(crate) fn build_async_runtime(action: impl std::future::Future) {
    tokio::runtime::Builder::new_multi_thread()
        .worker_threads(4)
        .enable_all()
        .build()
        .unwrap()
        .block_on(action);
}

static UNIQUE_ID: AtomicU64 = AtomicU64::new(0);

pub(crate) fn get_transaction_id() -> String {
    let id = UNIQUE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
    format!("TX{id}")
}

pub(crate) fn fill_describe(
    received: &mut MessageWrapperForReceived,
    source: &Message,
    preference: Option<&Arc<Preference>>,
) {
    received.name = source.name.clone();
    received.desc = source.desc.clone();
    let (is_match_ceid, is_match_vid) = if let Some(p_val) = preference {
        (
            p_val
                .collection_event
                .is_match_message(received.head.stream, received.head.function),
            p_val
                .variable
                .is_match_message(received.head.stream, received.head.function),
        )
    } else {
        (false, false)
    };
    // 遍历子级
    if let Some(recv_body) = received.body.as_mut() {
        if let Some(src_body) = source.body.as_ref() {
            fill_describe_for_value_ref(
                recv_body,
                src_body,
                is_match_ceid,
                is_match_vid,
                &preference,
                true,
            );
        }
    }
}

fn fill_describe_for_value_ref(
    target: &mut Value,
    source: &Value,
    is_match_ceid: bool,
    is_match_vid: bool,
    preference: &Option<&Arc<Preference>>,
    is_ignore_format: bool,
) {
    let inner = ValueInner::from(source);
    match target {
        Value::List {
            name,
            desc,
            mappging_ref,
            value: target_val,
        } => {
            if !is_ignore_format && inner.format != "List" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            if let Value::List {
                value: source_val, ..
            } = source
            {
                let mut target_iter = target_val.iter_mut();
                let mut source_iter = source_val.iter();
                let mut source_last = Option::None;
                loop {
                    if let Some(target_current) = target_iter.next() {
                        if let Some(source_current) = source_iter.next() {
                            source_last.replace(source_current);
                            fill_describe_for_value_ref(
                                target_current,
                                source_current,
                                is_match_ceid,
                                is_match_vid,
                                preference,
                                is_ignore_format,
                            );
                        } else if let Some(source_current) = source_last {
                            fill_describe_for_value_ref(
                                target_current,
                                source_current,
                                is_match_ceid,
                                is_match_vid,
                                preference,
                                is_ignore_format,
                            );
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        Value::Binary {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            if !is_ignore_format && inner.format != "Binary" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "Binary",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::Boolean {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            if !is_ignore_format && inner.format != "Boolean" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "Boolean",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::AscII {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            if !is_ignore_format && inner.format != "AscII" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "AscII",
                is_match_ceid,
                is_match_vid,
                preference,
                "1"
            );
        }
        Value::Jis8 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            if !is_ignore_format && inner.format != "Jis8" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "Jis8",
                is_match_ceid,
                is_match_vid,
                preference,
                "1"
            );
        }
        Value::I8 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            if !is_ignore_format && inner.format != "I8" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "I8",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::I1 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "I1" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "I1",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::I2 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "I2" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "I2",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::I4 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "I4" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "I4",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::F8 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "F8" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "F8",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::F4 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "F4" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "F4",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::U8 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "U8" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "U8",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::U1 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "U1" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "U1",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::U2 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "U2" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "U2",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
        Value::U4 {
            name,
            desc,
            mappging_ref,
            value,
        } => {
            let inner = ValueInner::from(source);
            if !is_ignore_format && inner.format != "u4" {
                return;
            }
            *name = inner.name.clone();
            *desc = inner.desc.clone();
            *mappging_ref = inner.mappging_ref.clone();
            fill_ceid_describe!(
                value,
                name,
                desc,
                "U4",
                is_match_ceid,
                is_match_vid,
                preference
            );
        }
    }
}

struct ValueInner<'a> {
    format: &'a str,
    name: &'a Option<String>,
    desc: &'a Option<String>,
    mappging_ref: &'a Option<String>,
}

impl<'a> ValueInner<'a> {
    fn from(val: &'a Value) -> Self {
        match val {
            Value::List {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "List",
                name,
                desc,
                mappging_ref,
            },
            Value::Binary {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "Binary",
                name,
                desc,
                mappging_ref,
            },
            Value::Boolean {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "Boolean",
                name,
                desc,
                mappging_ref,
            },
            Value::AscII {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "AscII",
                name,
                desc,
                mappging_ref,
            },
            Value::Jis8 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "Jis8",
                name,
                desc,
                mappging_ref,
            },
            Value::I8 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "I8",
                name,
                desc,
                mappging_ref,
            },
            Value::I1 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "I1",
                name,
                desc,
                mappging_ref,
            },
            Value::I2 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "I2",
                name,
                desc,
                mappging_ref,
            },
            Value::I4 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "I4",
                name,
                desc,
                mappging_ref,
            },
            Value::F8 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "F8",
                name,
                desc,
                mappging_ref,
            },
            Value::F4 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "F4",
                name,
                desc,
                mappging_ref,
            },
            Value::U8 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "U8",
                name,
                desc,
                mappging_ref,
            },
            Value::U1 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "U1",
                name,
                desc,
                mappging_ref,
            },
            Value::U2 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "U2",
                name,
                desc,
                mappging_ref,
            },
            Value::U4 {
                name,
                desc,
                mappging_ref,
                ..
            } => Self {
                format: "U4",
                name,
                desc,
                mappging_ref,
            },
        }
    }
}

pub(crate) fn find_matched_transaction<'a>(
    primary: &'a MessageWrapperForReceived,
    transactions: &'a Vec<TransactionTemplate>,
    match_policy: MatchPolicy,
) -> Option<&'a TransactionTemplate> {
    let mut result = None;
    for transaction in transactions {
        if transaction.primary.head.stream != primary.head.stream
            || transaction.primary.head.function != primary.head.function
        {
            continue;
        }
        if result.is_none() {
            result.replace(transaction);
        }
        match match_policy {
            MatchPolicy::None => {
                break;
            }
            MatchPolicy::Format => match (primary.body.as_ref(), transaction.primary.body.as_ref())
            {
                (Some(source), Some(target)) => {
                    if is_format_matched(source, target) {
                        result.replace(transaction);
                        return result;
                    }
                }
                _ => {}
            },
            MatchPolicy::FormatAndValue => {
                match (primary.body.as_ref(), transaction.primary.body.as_ref()) {
                    (Some(source), Some(target)) => {
                        if source == target {
                            result.replace(transaction);
                            return result;
                        }
                    }
                    _ => {}
                }
            }
        }
    }
    result
}

fn is_format_matched(source: &Value, target: &Value) -> bool {
    match (source, target) {
        (
            Value::List {
                value: source_val, ..
            },
            Value::List {
                value: target_val, ..
            },
        ) => {
            let mut source_iter = source_val.iter();
            let mut target_iter = target_val.iter();
            loop {
                match (source_iter.next(), target_iter.next()) {
                    (Some(val1), Some(val2)) => {
                        if !is_format_matched(val1, val2) {
                            return false;
                        }
                    }
                    (None, None) => {
                        return true;
                    }
                    _ => return false,
                }
            }
        }
        (Value::Binary { .. }, Value::Binary { .. }) => true,
        (Value::Boolean { .. }, Value::Boolean { .. }) => true,
        (Value::AscII { .. }, Value::AscII { .. }) => true,
        (Value::Jis8 { .. }, Value::Jis8 { .. }) => true,
        (Value::I8 { .. }, Value::I8 { .. }) => true,
        (Value::I2 { .. }, Value::I2 { .. }) => true,
        (Value::I4 { .. }, Value::I4 { .. }) => true,
        (Value::F8 { .. }, Value::F8 { .. }) => true,
        (Value::F4 { .. }, Value::F4 { .. }) => true,
        (Value::U8 { .. }, Value::U8 { .. }) => true,
        (Value::U1 { .. }, Value::U1 { .. }) => true,
        (Value::U2 { .. }, Value::U2 { .. }) => true,
        (Value::U4 { .. }, Value::U4 { .. }) => true,
        _ => false,
    }
}

pub(crate) fn parse_to_range<E>(
    idt: &str,
    min_str: &str,
    max_str: &str,
    o_value: &str,
) -> Result<MessageFlagPattern, E>
where
    E: serde::de::Error,
{
    let min = {
        match min_str.parse::<u8>() {
            Ok(n) => n,
            Err(err) => {
                return Err(serde::de::Error::custom(format!(
                    "error on parse min {} [{}] to u8, {}, original value = {}",
                    idt,
                    min_str,
                    err.to_string(),
                    o_value
                )));
            }
        }
    };
    let max = {
        match max_str.parse::<u8>() {
            Ok(n) => n,
            Err(err) => {
                return Err(serde::de::Error::custom(format!(
                    "error on parse max {} [{}] to u8, {}, original value = {}",
                    idt,
                    max_str,
                    err.to_string(),
                    o_value
                )));
            }
        }
    };
    if max < min {
        return Err(serde::de::Error::custom(format!(
            "The {} min value [{}] is larger than the max value [{}], original value = {}",
            idt, min, max, o_value
        )));
    }
    Ok(MessageFlagPattern::Range(min, max))
}

pub(crate) fn parse_to_exact<E>(
    idt: &str,
    value: &str,
    o_value: &str,
) -> Result<MessageFlagPattern, E>
where
    E: serde::de::Error,
{
    match value.parse::<u8>() {
        Ok(n) => Ok(MessageFlagPattern::Exact(n)),
        Err(err) => Err(serde::de::Error::custom(format!(
            "error on parse {} [{}] to u8, {}, original value = {}",
            idt,
            value,
            err.to_string(),
            o_value
        ))),
    }
}

// pub(crate) fn fill_ceid(value: &mut Value, source: &Vec<CollectionEventItem>) {
//     match value {
//         Value::List { value, .. } => {
//             for val in value.iter_mut() {
//                 fill_ceid(val, source);
//             }
//         }
//         Value::Binary {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "Binary", source);
//         }
//         Value::Boolean {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "Boolean", source);
//         }
//         Value::AscII {
//             name, desc, value, ..
//         }
//         | Value::Jis8 {
//             name, desc, value, ..
//         } => {
//             if let Some(name) = name {
//                 if name == STR_CEID {
//                     for item in source.iter() {
//                         if item.format == "AscII" && &item.id == value {
//                             append_option_str(desc, &item.desc);
//                             break;
//                         }
//                     }
//                 }
//             }
//         }
//         Value::I8 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "I8", source);
//         }
//         Value::I1 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "I1", source);
//         }
//         Value::I2 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "I2", source);
//         }
//         Value::I4 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "I4", source);
//         }
//         Value::F8 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "F8", source);
//         }
//         Value::F4 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "F4", source);
//         }
//         Value::U8 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "U8", source);
//         }
//         Value::U1 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "U1", source);
//         }
//         Value::U2 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "U2", source);
//         }
//         Value::U4 {
//             name, desc, value, ..
//         } => {
//             fill_ceid_inner!(value, name, desc, "U4", source);
//         }
//     }
// }

fn append_option_str(source: &mut Option<String>, str: &str) {
    if let Some(s) = source {
        s.insert_str(0, &format!("{str}  "));
    } else {
        source.replace(str.to_string());
    }
}
